package com.xbongbong.workflow.service.strategy.data.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.FlowStatusEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.enums.TaskTypeEnum;
import com.xbongbong.paas.pojo.dto.SaasFormSaveDTO;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.Arith;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.util.ExplainUtil;
import com.xbongbong.paas.util.FormDataUtil;
import com.xbongbong.pro.constant.BusinessConstant;
import com.xbongbong.pro.domain.entity.UpdateDataEntity;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.formdata.pojo.SaasNeedRedundantAttrPojo;
import com.xbongbong.pro.product.pojo.dto.CostRecalculationDTO;
import com.xbongbong.pro.workflow.enums.WorkflowOperateEnum;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.ParameterConstant;
import com.xbongbong.saas.domain.entity.InstockProductEntity;
import com.xbongbong.saas.domain.entity.SmartReplenishmentEntity;
import com.xbongbong.saas.domain.entity.ext.InstockEntityExt;
import com.xbongbong.saas.domain.entity.ext.WarehouseEntityExt;
import com.xbongbong.saas.enums.InstockTypeEnum;
import com.xbongbong.saas.enums.SelectProductEnum;
import com.xbongbong.saas.enums.StockTypeEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.InstockEnum;
import com.xbongbong.saas.enums.business.ProductEnum;
import com.xbongbong.saas.enums.business.WarehouseEnum;
import com.xbongbong.saas.enums.dictionary.WarehouseOriStockEnum;
import com.xbongbong.saas.help.ReceivablesHelper;
import com.xbongbong.saas.help.workflow.BatchFlowBillHelp;
import com.xbongbong.saas.help.workflow.InstockHelp;
import com.xbongbong.saas.help.workflow.ProductSerialHelp;
import com.xbongbong.saas.help.workflow.StockFlowBillHelp;
import com.xbongbong.saas.model.InstockModel;
import com.xbongbong.saas.model.InstockProductModel;
import com.xbongbong.saas.model.PaasFormSubDataModel;
import com.xbongbong.saas.model.SmartReplenishmentModel;
import com.xbongbong.saas.model.WarehouseModel;
import com.xbongbong.workflow.domain.entity.WorkflowBackupDataEntity;
import com.xbongbong.workflow.model.WorkflowBackupDataModel;
import com.xbongbong.workflow.pojo.Data;
import com.xbongbong.workflow.pojo.WorkflowTransferPOJO;
import com.xbongbong.workflow.service.strategy.data.AbstractWorkflowDataStrategy;
import com.xbongbong.workflow.service.strategy.data.WorkflowDataProcessStrategy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

/**
 *
 * @author 魏荣杰
 *
 */
@Service
public class WorkflowInstockStrategy extends AbstractWorkflowDataStrategy implements WorkflowDataProcessStrategy {


    private static final Logger log = LoggerFactory.getLogger(WorkflowInstockStrategy.class);

    @Resource
    private ProductSerialHelp productSerialHelp;
    @Resource
    private StockFlowBillHelp stockFlowBillHelp;
    @Resource
    private InstockModel instockModel;
    @Resource
    private BatchFlowBillHelp batchFlowBillHelp;
    @Resource
    private InstockHelp instockHelp;
    @Resource
    private WorkflowBackupDataModel workflowBackupDataModel;
    @Resource
    private InstockProductModel instockProductModel;
    @Resource
    private WarehouseModel warehouseModel;
    @Resource
    private PaasFormSubDataModel paasFormSubDataModel;
    @Resource
    private ReceivablesHelper receivablesHelper;
    @Resource
    private SmartReplenishmentModel smartReplenishmentModel;


    @Override
    public List<Integer> type() {
        return Arrays.asList(XbbRefTypeEnum.INSTOCK.getCode(), XbbRefTypeEnum.PURCHASE_INSTOCK.getCode(), XbbRefTypeEnum.REFUND_INSTOCK.getCode(), XbbRefTypeEnum.OTHER_INSTOCK.getCode(), XbbRefTypeEnum.PRODUCTION_INSTOCK.getCode(), XbbRefTypeEnum.RETURNED_MATERIEL_INSTOCK.getCode());
    }

    @Override
    public void save(WorkflowTransferPOJO workflowTransferPOJO, SaasNeedRedundantAttrPojo saasNeedRedundantAttrPojo) throws XbbException {
        // 文件柜
        saveDataCabinetFile(workflowTransferPOJO);


        String corpid = workflowTransferPOJO.getCorpid();
        Data pojoData = workflowTransferPOJO.getData();
        JSONObject data = pojoData.getData();
        Long dataId = pojoData.getId();
        Long formId = pojoData.getFormId();

        InstockEntityExt instockEntityExt = instockModel.getByKey(dataId, corpid);
        instockEntityExt.setData(data);

        // 逻辑改为仅新建进行入库单保存后逻辑：产品保存，库存更新，上游单据更新
        JSONArray productJsonArray = data.getJSONArray(InstockEnum.PRODUCT.getAttr());
        String productStr = productJsonArray.toJSONString();
        Integer type = data.getInteger(InstockEnum.TYPE.getAttr());
        Long refId = Objects.isNull(data.getLong(InstockEnum.REF_ID.getAttr())) ? 0L : data.getLong(InstockEnum.REF_ID.getAttr());

        Map<String, Object> param = new HashMap<>();
        param.put(ParameterConstant.CORPID, corpid);
        param.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
        param.put("type", type);
        param.put("refId", refId);
        param.put("intoWarehouseId", dataId);
        List<InstockProductEntity> instockProductModelEntitys = instockProductModel.findEntitys(param);
        Set<Long> warehouseIdList = new HashSet<>();
        Map<Long,Long> productIdMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long,Long> refProductIdMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (InstockProductEntity instockProductEntity:instockProductModelEntitys){
            warehouseIdList.add(instockProductEntity.getWarehouseId());
            productIdMap.put(instockProductEntity.getProductId(),instockProductEntity.getParentId());
            refProductIdMap.put(instockProductEntity.getProductId(),instockProductEntity.getId());
        }
        Map<Long, JSONObject> productMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if (CollectionsUtil.isNotEmpty(productJsonArray)) {
            for (int i = 0; i < productJsonArray.size(); i++) {
                JSONObject productObject = productJsonArray.getJSONObject(i);
                Long productId = productObject.getLong(SelectProductEnum.PRODUCT.getAttr());
                productObject.put(ProductEnum.PARENT_ID.getSaasAttr(), productIdMap.get(productId));
                if (Objects.equals(InstockTypeEnum.RETURNED_MATERIEL_INSTOCK.getCode(), type)) {
                    if (Objects.isNull(productObject.get(BusinessConstant.PRODUCT_SUB_ID))) {
                        productObject.put(BusinessConstant.PRODUCT_SUB_ID, refProductIdMap.get(productId));
                    }
                }
                productMap.put(productObject.getLong(BusinessConstant.PRODUCT_SUB_ID), productObject);
            }
        }
        data.put(InstockEnum.PRODUCT.getAttr(),productJsonArray);
        param.clear();
        param.put(ParameterConstant.CORPID,corpid);
        param.put(ParameterConstant.ID_IN,warehouseIdList);
        param.put(ParameterConstant.DEL,DelEnum.NORMAL.getDel());
        List<WarehouseEntityExt> warehouseEntityExts = warehouseModel.findEntitys(param);
        if (CollectionsUtil.isNotEmpty(warehouseEntityExts)){
            List<UpdateDataEntity> updateDataEntities = new ArrayList<>();
            for(WarehouseEntityExt warehouseEntityExt : warehouseEntityExts){
                if (Objects.nonNull(warehouseEntityExt.getData()) && !Objects.equals(warehouseEntityExt.getData().getString(WarehouseEnum.ORI_STOCK.getAttr()), WarehouseOriStockEnum.NO_NEED.getCode())) {
                    JSONObject updateData = new JSONObject();
                    updateData.put(WarehouseEnum.ORI_STOCK.getAttr(), WarehouseOriStockEnum.NO_NEED.getCode());
                    updateDataEntities.add(ExplainUtil.getUpdateData(warehouseEntityExt.getId(), updateData, corpid));
                }
            }
            if (!updateDataEntities.isEmpty()) {
                warehouseModel.updateBatchImmediately(updateDataEntities, corpid);
            }
        }
        // 更新入库单产品的分仓库存、批次库存
        instockHelp.addUpdateStock(instockProductModelEntitys, corpid, false);

        // 完成工作流，将序列号插入到序列号流水表，并且插入结存表
        productSerialHelp.saveSerial(corpid, pojoData.getBusinessType(), data, dataId, data.getString(BasicConstant.SERIAL_NO), productMap);
        // 更改关联单据状态
        instockHelp.setIntstockDocumentsNew(corpid, data, instockEntityExt);
        //发送重算消息
        CostRecalculationDTO costRecalculationDTO = new CostRecalculationDTO();
        SaasFormSaveDTO saasFormSaveDTOCost = new SaasFormSaveDTO();
        saasFormSaveDTOCost.setCorpid(corpid);
        saasFormSaveDTOCost.setBusinessType(pojoData.getBusinessType());
        saasFormSaveDTOCost.setNewData(data);
        saasFormSaveDTOCost.setNewPaasFormDataEntity(instockEntityExt);
        costRecalculationDTO.setType(StockTypeEnum.IN_STOCK.getCode());
        costRecalculationDTO.setData(data);
        costRecalculationDTO.setStockId(dataId);
        costRecalculationDTO.setCorpid(corpid);
        costRecalculationDTO.setMark(BasicConstant.ONE);
        costRecalculationDTO.setIsWorkFlow(BasicConstant.ZERO);
        costRecalculationDTO.setSaasFormSaveDTO(saasFormSaveDTOCost);
        //将流水放至重算方法中生成，保证处理的先后顺序
        //log.info("参数信息："+ JSONUtils.toJSONString(costRecalculationDTO));
        /*stockFlowBillHelp.caculateStockModification4Save(corpid, pojoData.getBusinessType(), data, instockEntityExt);
        batchFlowBillHelp.batchFlowModification4Save(corpid, pojoData.getBusinessType(), data, instockEntityExt);*/
        receivablesHelper.costRecalculationWorkFlow(costRecalculationDTO);

        // 退货入库单修复合同成本
        if(Objects.equals(type, InstockTypeEnum.RED_CONTRACT_INSTOCK.getCode())){
            Set<Long> refIdSet = new HashSet<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            refIdSet.add(refId);
            instockHelp.afterSaveRefundInstock4ContractCost(corpid, refIdSet, true, productJsonArray);
        }
        addLinkDataDynamic(workflowTransferPOJO);
        // api
        apiHook(workflowTransferPOJO);
        // log
        afterSaveLog(workflowTransferPOJO);
    }

    @Override
    public void update(WorkflowTransferPOJO workflowTransferPOJO, SaasNeedRedundantAttrPojo saasNeedRedundantAttrPojo) throws XbbException {
        // 文件柜
        saveDataCabinetFile(workflowTransferPOJO);

        // api
        apiHook(workflowTransferPOJO);
        // log
        afterUpdateLog(workflowTransferPOJO);
    }

    @Override
    public void updateBack(Long taskId, WorkflowTransferPOJO workflowTransferPOJO) throws XbbException{
        try {
            String corpid = workflowTransferPOJO.getCorpid();
            Long backupDataId = workflowTransferPOJO.getBackupDataId();
            Long dataId = workflowTransferPOJO.getData().getId();
            WorkflowBackupDataEntity workflowBackupDataEntity = workflowBackupDataModel.getByKey(backupDataId, corpid);
            if (Objects.nonNull(workflowBackupDataEntity)) {
                JSONObject data = workflowBackupDataEntity.getData();

                replenishAttrForBackupData(workflowTransferPOJO.getData().getData(), data);

                InstockEntityExt instockEntityExt = new InstockEntityExt();
                instockEntityExt.setId(dataId);
                instockEntityExt.setCorpid(corpid);
                instockEntityExt.setData(data);
                instockEntityExt.setSerialNo(data.getString(FieldTypeEnum.SERIALNO.getAlias()));
                // 获取负责人
                instockEntityExt.setOwnerId(getOwnerId(data));
                instockEntityExt.setDepartmentId(data.getLong(FieldTypeEnum.DEPARTMENTID.getAlias()));

                FormDataUtil.removeSystemData(data);
                if (Objects.equals(workflowTransferPOJO.getOperate(), WorkflowOperateEnum.UPDATE.getType())) {
                    instockEntityExt.setFlowStatus(FlowStatusEnum.PASS.getType());
                }
                instockModel.update(instockEntityExt);

                // 回退被删掉的子表单
                updateBackSubForm(instockEntityExt, corpid, IndexTypeEnum.IDX_SAAS_INSTOCK_SUB);
                //回退被删掉的富文本
                updateBackRichText(taskId, workflowTransferPOJO);
            }
        } catch (Exception e) {
            log.error("com.xbongbong.workflow.service.strategy.data.impl.WorkflowInstockStrategy.updateBack error ", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }
    }

    @Override
    public void approvalFailed(Long taskId, WorkflowTransferPOJO workflowTransferPOJO, Integer taskType) throws XbbException {
        try {
            String corpid = workflowTransferPOJO.getCorpid();
            Data workflowData = workflowTransferPOJO.getData();
            Long dataId = workflowData.getId();
            Long formId = workflowData.getFormId();
            Integer businessType = workflowData.getBusinessType();
            Integer saasMark = workflowData.getSaasMark();
            InstockEntityExt instockEntityExt = new InstockEntityExt();
            instockEntityExt.setId(dataId);
            if (Objects.equals(TaskTypeEnum.REVOKE.getType(), taskType)) {
                instockEntityExt.setFlowStatus(FlowStatusEnum.REVOKE.getType());
            } else {
                instockEntityExt.setFlowStatus(FlowStatusEnum.REJECT.getType());
            }
            instockEntityExt.setCorpid(corpid);
            instockEntityExt.setUpdateTime(DateTimeUtil.getInt());
            instockModel.update(instockEntityExt);
            // 子表单
            DelEnum del = DelEnum.APPROVE_FAILED;

            paasFormSubDataModel.deleteBatchByDataId(Collections.singletonList(dataId), corpid, IndexTypeEnum.IDX_SAAS_INSTOCK_SUB, del);
            //富文本
            deleteFormRichText(dataId, corpid, formId, businessType, saasMark, DelEnum.NORMAL);

            // 关联产品
            List<InstockProductEntity> productList = instockProductModel.getProductsByInstockIdIn(corpid, Arrays.asList(dataId));
            if (CollectionsUtil.isNotEmpty(productList)) {
                List<Long> idIn = new ArrayList<>();
                productList.forEach(item->idIn.add(item.getId()));
                instockProductModel.deleteBatchById(idIn, corpid, del.getDel());
                // 回退智能补货数据
                Map<Long,Double> numMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                Set<Long> productIdset = new HashSet<>();
                for (InstockProductEntity entity : productList) {
                    Long productId = entity.getProductId();
                    productIdset.add(productId);
                    Double productNum = entity.getProductNum();
                    if (numMap.containsKey(productId)){
                        numMap.put(productId, Arith.add(numMap.get(productId),productNum));
                    }else {
                        numMap.put(productId,productNum);
                    }
                }
                if (CollectionsUtil.isNotEmpty(productIdset)){
                    List<SmartReplenishmentEntity> smartReplenishmentEntities = smartReplenishmentModel.getByProductList(corpid, new ArrayList<>(productIdset));
                    if (CollectionsUtil.isNotEmpty(smartReplenishmentEntities)){
                        for (SmartReplenishmentEntity smartReplenishmentEntity : smartReplenishmentEntities) {
                            Long productId = smartReplenishmentEntity.getProductId();
                            Double pendingInstockNum = smartReplenishmentEntity.getPendingInstockNum();
                            Double delNum = numMap.getOrDefault(productId, 0D);
                            smartReplenishmentEntity.setPendingInstockNum(Arith.add(pendingInstockNum,delNum));
                        }
                        smartReplenishmentModel.updateBatch(smartReplenishmentEntities,corpid);
                    }
                }
            }
        } catch (Exception e) {
            log.error("com.xbongbong.workflow.service.strategy.data.impl.WorkflowInstockStrategy.approvalFailed error ", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }
    }


}
